package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.common.constants.WemediaConstants;
import com.heima.common.constants.WmNewsMessageConstants;
import com.heima.common.exception.CustomException;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.mess.UpOrDownMess;
import com.heima.model.wemedia.dtos.WmNewsDto;
import com.heima.model.wemedia.dtos.WmNewsPageReqDto;
import com.heima.model.wemedia.pojos.WmMaterial;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmNewsMaterial;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.thread.WmThreadLocalUtil;
import com.heima.wemedia.mapper.WmMaterialMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmNewsMaterialMapper;
import com.heima.wemedia.service.WmNewsAutoScanService;
import com.heima.wemedia.service.WmNewsService;
import com.heima.wemedia.service.WmNewsTaskService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {

    @Autowired
    WmNewsMaterialMapper wmNewsMaterialMapper;
    @Autowired
    WmMaterialMapper wmMaterialMapper;
    @Autowired
    WmNewsAutoScanService wmNewsAutoScanService;
    @Autowired
    KafkaTemplate<String, String> kafkaTemplate;
    @Autowired
    WmNewsTaskService wmNewsTaskService;


    @Override
    public ResponseResult list(WmNewsPageReqDto dto) {
        //1.校验
        if(dto==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        if(WmThreadLocalUtil.getUser()==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);//必须登陆才能访问
        }
        dto.checkParam();

        //2.分页条件查询
        IPage<WmNews> pageParam = new Page<>(dto.getPage(), dto.getSize());//参数一是页码，参数二是每页条数
        LambdaQueryWrapper<WmNews> wrapper = new LambdaQueryWrapper<>();
        if(dto.getChannelId()!=null){
            wrapper.eq(WmNews::getChannelId, dto.getChannelId());//频道条件
        }
        if(dto.getStatus()!=null){
            wrapper.eq(WmNews::getStatus, dto.getStatus());//文章状态
        }
        if(StringUtils.isNotBlank(dto.getKeyword())){
            wrapper.like(WmNews::getTitle, dto.getKeyword());//文章标题模糊查询
        }
        if(dto.getBeginPubDate()!=null && dto.getEndPubDate()!=null){
            wrapper.between(WmNews::getPublishTime, dto.getBeginPubDate(), dto.getEndPubDate());//按发布时间区间查询
        }
        //只能查询自己的文章
        wrapper.eq(WmNews::getUserId, WmThreadLocalUtil.getUser().getId());
        //按文章发布时间倒序
        wrapper.orderByDesc(WmNews::getPublishTime);

        IPage<WmNews> page = page(pageParam, wrapper);//参数一是分页对象，参数二是条件

        //3.返回
        PageResponseResult result = new PageResponseResult(dto.getPage(), dto.getSize(), (int) page.getTotal());
        result.setData(page.getRecords());
        return result;
    }


    @Override
    @Transactional
    public ResponseResult submit(WmNewsDto dto) {
        //线程名称:  http-nio-51803-exec-6  是tomcat默认的线程
        log.info("线程名称:  {},   发布文章参数：{}", Thread.currentThread().getName(),  dto);
        //1.校验
        if(dto==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        if(StringUtils.isBlank(dto.getTitle())){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        if(dto.getChannelId()==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        WmUser user = WmThreadLocalUtil.getUser();
        if(user==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        //其他校验.....


        //2.创建WmNews实例，并接受dto中的参数
        WmNews wmNews = new WmNews();




        //将内容中的图片抽到到集合中
        String content = dto.getContent();
        Set<String> contentImgUrls = new HashSet<>();//代表内容中图片的路径集合
        if(StringUtils.isNotBlank(content)){
            List<Map> mapList = JSON.parseArray(content, Map.class);
            for (Map map : mapList) {
                if(map!=null && "image".equals(map.get("type"))){
                    String imgUrl = (String)map.get("value");
                    if(StringUtils.isNotBlank(imgUrl)){
                        contentImgUrls.add(imgUrl);
                    }
                }
            }
        }
        //3.自动选择封面处理  dto中的type值是不是-1
        List<String> contentImageUrllist = new ArrayList<>(contentImgUrls);//将set转为list
        if(dto.getType()!=null && WemediaConstants.WM_NEWS_TYPE_AUTO.equals(dto.getType())){
            int size = contentImgUrls.size();//获取内容中图片的数量
            if(size>=3){ //取3张作为封面
                //List<String> collect = contentImgUrls.stream().limit(3).collect(Collectors.toList());//stream流从set中获取3个元素
                //dto.setImages(collect);
                List<String> subList = contentImageUrllist.subList(0, 3);//从list中截取三个元素
                dto.setImages(subList);
                dto.setType(WemediaConstants.WM_NEWS_MANY_IMAGE);
            }else if(size>=1){ //取1张作为封面
                List<String> subList = contentImageUrllist.subList(0, 1);//从list中截取三个元素
                dto.setImages(subList);
                dto.setType(WemediaConstants.WM_NEWS_SINGLE_IMAGE);
            }else{//无图
                dto.setType(WemediaConstants.WM_NEWS_NONE_IMAGE);
            }
        }


        BeanUtils.copyProperties(dto, wmNews);
        if(dto.getImages()!=null && dto.getImages().size()>0){
            wmNews.setImages(StringUtils.join(dto.getImages(), ","));
        }
        wmNews.setSubmitedTime(new Date());


        //4.保存文章（如果携带id则修改，否则新增）   (草稿 和 提交审核  都走)
        if(wmNews.getId()!=null){
            //修改
            //delete from wm_news_material where news_id=  xxxx
            wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery().eq(WmNewsMaterial::getNewsId, wmNews.getId()));
            updateById(wmNews);
        }else{
            //新增
            wmNews.setCreatedTime(new Date());
            wmNews.setUserId(WmThreadLocalUtil.getUser().getId());
            wmNews.setEnable((short)1);
            save(wmNews);
        }


        //5.判断是否是草稿（草稿不保存文章和素材关联关系，直接返回，而不是抛异常）
        if(dto.getStatus()!=null && dto.getStatus().equals(WmNews.Status.NORMAL.getCode())){
            return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
        }


        //6.保存关联关系(文章和封面中的图片关联关系  文章和内容中的图片关联关系)（提交审核时才会保存关联关系）
        saveNewsAndMaterialRelation(dto.getImages(), wmNews.getId(), WemediaConstants.WM_COVER_REFERENCE);//保存封面中的图片和文章关联关系
        saveNewsAndMaterialRelation(contentImageUrllist, wmNews.getId(), WemediaConstants.WM_CONTENT_REFERENCE);//保存内容中的图片和文章关联关系




        //开启一个线程  异步审核文章
        //wmNewsAutoScanService.autoScanWnNews(wmNews.getId());

        wmNewsTaskService.addNewsToTask(wmNews);



        //7.返回
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 保存文章和素材关联关系
     * @param images   封面 或者 内容的素材url集合
     * @param newsId  文章id
     * @param type   为0代表时内容中的素材     为1代表谁封面中的素材
     */
    private void saveNewsAndMaterialRelation(List<String> images, Integer newsId, Short type) {
        //1.校验
        if(images==null || images.size()==0){
            return;
        }

        //2.根据url集合查询素材的id集合      select * from wm_material where url in (xxx,xxx,xxx)
        List<WmMaterial> wmMaterials = wmMaterialMapper.selectList(Wrappers.<WmMaterial>lambdaQuery().in(WmMaterial::getUrl, images));
        /*List<Integer> ids = new ArrayList<>();
        for (WmMaterial wmMaterial : wmMaterials) {
            ids.add(wmMaterial.getId());
        }*/
        List<Integer> ids = wmMaterials.stream().map(WmMaterial::getId).collect(Collectors.toList());//获取url集合对应的 id集合


        //3.校验是否有素材失效，如果有素材失效了直接抛出异常
        if(ids==null || ids.size()==0 || ids.size()!=images.size()){
            throw new CustomException(AppHttpCodeEnum.MATERIASL_REFERENCE_FAIL);
        }

        //4.保存关联关系（批量保存wm_news_material）
        wmNewsMaterialMapper.saveRelation(ids, newsId, type);
    }



    @Override
    public ResponseResult downOrUp(WmNewsDto dto) {
        //1.校验（是否为空   文章id是否正确   文章的状态是否是已发布）
        if(dto==null || dto.getId()==null || dto.getEnable()==null ){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        if(dto.getEnable()>1 || dto.getEnable()<0){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        WmNews wmNews = getById(dto.getId());
        if(wmNews==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"文章不存在");
        }
        if(wmNews.getStatus()==null || !wmNews.getStatus().equals(WmNews.Status.PUBLISHED.getCode())){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "文章状态不是已发布，不能操作上下架");
        }

        //2.修改文章enable   0是下架  1是上海
        //update wm_news set enable=xxx where id =xxx
        update(Wrappers.<WmNews>lambdaUpdate()
                .set(WmNews::getEnable, dto.getEnable())
                .eq(WmNews::getId, dto.getId()));

        //3.发送消息到kafka  消息内容包括文章id  上下架状态
        /**
         * wemedia服务整合kafka步骤
         * 1、导依赖
         * 2、添加kafka配置
         * 3、kafkatemplate发消息    kafkalistener收消息
         */
        UpOrDownMess mess = new UpOrDownMess();
        mess.setArticleId(wmNews.getArticleId());
        mess.setEnable(dto.getEnable());//0是下架  1是上架
        log.info("自媒体发送消息到kafka   {}", JSON.toJSONString(mess));
        kafkaTemplate.send(WmNewsMessageConstants.WM_NEWS_UP_OR_DOWN_TOPIC, JSON.toJSONString(mess));

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    public static void main(String[] args) {
        ArrayList<String> strings = new ArrayList<>();
        strings.add("aaa");
        strings.add("bbb");
        strings.add("ccc");
        strings.add("ddd");
        List<String> strings1 = strings.subList(0, 3);
        System.out.println(strings1);

        System.out.println(StringUtils.join(strings, ","));
    }





}
